<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue'
import { Editor, EditorContent } from '@tiptap/vue-3'
import { Color, TextStyle } from '@tiptap/extension-text-style'
import StarterKit from '@tiptap/starter-kit'
import { ListItem } from '@tiptap/extension-list'

// 定义编辑器实例
const editor = ref<Editor | null>(null)
const content = ref(`
      <h2>
        Hi there,
      </h2>
      <p>
        this is a <em>basic</em> example of <strong>Tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
      </p>
      <ul>
        <li>
          That’s a bullet list with one …
        </li>
        <li>
          … or two list items.
        </li>
      </ul>
      <p>
        Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
      </p>
      <pre><code class="language-css">body {
  display: none;
}</code></pre>
      <p>
        I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
      </p>
      <blockquote>
        Wow, that’s amazing. Good work, boy! 👏
        <br />
        — Mom
      </blockquote>
    `)
// 按钮点击处理函数
const handleCommand = (command: () => void, canCommand?: () => boolean) => {
    if (canCommand && !canCommand()) return
    command()
}

// 检查是否激活
const isActive = (type: string, options?: Record<string, any>) => {
    if (!editor.value) return false
    return editor.value.isActive(type, options)
}

// 组件挂载后初始化编辑器
onMounted(() => {
    editor.value = new Editor({
        extensions: [
            Color.configure({ types: [TextStyle.name, ListItem.name] }),
            TextStyle.configure({}),
            StarterKit,
        ],
        content: content.value,
    })
})

// 组件卸载前销毁编辑器
onBeforeUnmount(() => {
    if (editor.value) {
        editor.value.destroy()
    }
})
</script>

<template>
    <div v-if="editor" class="container">
        <div class="control-group">
            <div class="button-group">
                <button @click="handleCommand(
                    () => editor?.chain().focus().toggleBold().run(),
                    () => editor?.can().chain().focus().toggleBold().run()
                )" :disabled="!editor.can().chain().focus().toggleBold().run()"
                    :class="{ 'is-active': isActive('bold') }">
                    Bold
                </button>
                <button @click="handleCommand(
                    () => editor?.chain().focus().toggleItalic().run(),
                    () => editor?.can().chain().focus().toggleItalic().run()
                )" :disabled="!editor.can().chain().focus().toggleItalic().run()"
                    :class="{ 'is-active': isActive('italic') }">
                    Italic
                </button>
                <button @click="handleCommand(
                    () => editor?.chain().focus().toggleStrike().run(),
                    () => editor?.can().chain().focus().toggleStrike().run()
                )" :disabled="!editor.can().chain().focus().toggleStrike().run()"
                    :class="{ 'is-active': isActive('strike') }">
                    Strike
                </button>
                <button @click="handleCommand(
                    () => editor?.chain().focus().toggleCode().run(),
                    () => editor?.can().chain().focus().toggleCode().run()
                )" :disabled="!editor.can().chain().focus().toggleCode().run()"
                    :class="{ 'is-active': isActive('code') }">
                    Code
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().unsetAllMarks().run())">
                    Clear marks
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().clearNodes().run())">
                    Clear nodes
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().setParagraph().run())"
                    :class="{ 'is-active': isActive('paragraph') }">
                    Paragraph
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 1 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 1 }) }">
                    H1
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 2 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 2 }) }">
                    H2
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 3 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 3 }) }">
                    H3
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 4 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 4 }) }">
                    H4
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 5 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 5 }) }">
                    H5
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleHeading({ level: 6 }).run())"
                    :class="{ 'is-active': isActive('heading', { level: 6 }) }">
                    H6
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleBulletList().run())"
                    :class="{ 'is-active': isActive('bulletList') }">
                    Bullet list
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleOrderedList().run())"
                    :class="{ 'is-active': isActive('orderedList') }">
                    Ordered list
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleCodeBlock().run())"
                    :class="{ 'is-active': isActive('codeBlock') }">
                    Code block
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().toggleBlockquote().run())"
                    :class="{ 'is-active': isActive('blockquote') }">
                    Blockquote
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().setHorizontalRule().run())">
                    Horizontal rule
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().setHardBreak().run())">
                    Hard break
                </button>
                <button @click="handleCommand(
                    () => editor?.chain().focus().undo().run(),
                    () => editor?.can().chain().focus().undo().run()
                )" :disabled="!editor.can().chain().focus().undo().run()">
                    Undo
                </button>
                <button @click="handleCommand(
                    () => editor?.chain().focus().redo().run(),
                    () => editor?.can().chain().focus().redo().run()
                )" :disabled="!editor.can().chain().focus().redo().run()">
                    Redo
                </button>
                <button @click="handleCommand(() => editor?.chain().focus().setColor('#958DF1').run())"
                    :class="{ 'is-active': isActive('textStyle', { color: '#958DF1' }) }">
                    Purple
                </button>
            </div>
        </div>
        <EditorContent :editor="editor" />
    </div>
    {{ content }}
</template>

<style lang="scss" scoped>
.container {
    .control-group {
        margin-bottom: 0.5rem;

        .button-group {
            display: flex;
            flex-wrap: wrap;
            gap: 0.25rem;
            padding: 0.5rem;
            background-color: #f5f5f5;
            border-radius: 0.5rem;
            overflow-x: auto;

            button {
                padding: 0.25rem 0.5rem;
                border: 1px solid #ddd;
                background-color: white;
                cursor: pointer;
                font-size: 0.875rem;
                border-radius: 0.25rem;

                &:disabled {
                    opacity: 0.5;
                    cursor: not-allowed;
                }

                &.is-active {
                    background-color: #007acc;
                    color: white;
                    border-color: #007acc;
                }

                &:not(:disabled):hover {
                    background-color: #f0f0f0;
                }
            }
        }
    }
}

/* Basic editor styles */
.tiptap {
    :first-child {
        margin-top: 0;
    }

    /* List styles */
    ul,
    ol {
        padding: 0 1rem;
        margin: 1.25rem 1rem 1.25rem 0.4rem;

        li p {
            margin-top: 0.25em;
            margin-bottom: 0.25em;
        }
    }

    /* Heading styles */
    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
        line-height: 1.1;
        margin-top: 2.5rem;
        text-wrap: pretty;
    }

    h1,
    h2 {
        margin-top: 3.5rem;
        margin-bottom: 1.5rem;
    }

    h1 {
        font-size: 1.4rem;
    }

    h2 {
        font-size: 1.2rem;
    }

    h3 {
        font-size: 1.1rem;
    }

    h4,
    h5,
    h6 {
        font-size: 1rem;
    }

    /* Code and preformatted text styles */
    code {
        background-color: var(--purple-light);
        border-radius: 0.4rem;
        color: var(--black);
        font-size: 0.85rem;
        padding: 0.25em 0.3em;
    }

    pre {
        background: var(--black);
        border-radius: 0.5rem;
        color: var(--white);
        font-family: 'JetBrainsMono', monospace;
        margin: 1.5rem 0;
        padding: 0.75rem 1rem;

        code {
            background: none;
            color: inherit;
            font-size: 0.8rem;
            padding: 0;
        }
    }

    blockquote {
        border-left: 3px solid var(--gray-3);
        margin: 1.5rem 0;
        padding-left: 1rem;
    }

    hr {
        border: none;
        border-top: 1px solid var(--gray-2);
        margin: 2rem 0;
    }
}
</style>